﻿using System;
using System.Reflection;
using K9Nano.Configuration.Startup;
using K9Nano.Share.Exceptions;
using K9Nano.Share.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

namespace K9Nano.Dependency
{
    public static class AssemblyRegisterExtensions
    {
        public static IServiceCollection RegisterConventionalAssembly(this IServiceCollection services, params Assembly[] assemblies)
        {
            foreach (var assembly in assemblies)
            {
                var classes = assembly.GetClasses(StartupConfiguration.Global.ClassFilterFactory);
                foreach (var implType in classes)
                {
                    if (implType.IsGenericTypeDefinition)
                    {
                        throw new K9Exception($"Cannot register {implType} for conventional register does not support generic type. Please register it manually.");
                    }

                    var serviceTypes = StartupConfiguration.Global.DependencyConvention.GetServiceTypes(implType);
                    Action<Type, Type> register;
                    if (typeof(ITransientDependency).IsAssignableFrom(implType))
                    {
                        register = services.TryAddTransient;
                    }
                    else if (typeof(IScopedDependency).IsAssignableFrom(implType))
                    {
                        register = services.TryAddScoped;
                    }
                    else
                    {
                        register = services.TryAddSingleton;
                    }

                    if (serviceTypes.Length > 0)
                    {
                        foreach (var serviceType in serviceTypes)
                        {
                            register(serviceType, implType);
                        }
                    }
                    else
                    {
                        register(implType, implType);
                    }
                }
            }

            return services;
        }
    }
}